package com.hudson.broker.handler.netty;

import com.hudson.broker.client.NameSrvClient;
import io.netty.channel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: 渔小鲤
 * @DateTime: 2025/7/12 22:35
 **/
public class ReconnectionHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(ReconnectionHandler.class);
    private final String address;
    private final int port;

    private final int maxRetries = 10; // 最大重试次数
    private final long initialDelay = 2; // 初始延迟时间(秒)
    private final long maxDelay = 60; // 最大延迟时间(秒)

    // 新增字段保存 ScheduledFuture 和重连计数
    private ScheduledFuture<?> reconnectFuture;
    private final AtomicInteger retryCount = new AtomicInteger(0);

    public ReconnectionHandler(String address, int port) {
        this.address = address;
        this.port = port;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("连接已建立: {}:{}", address, port);
        // 连接成功时重置重试计数
        retryCount.set(0);
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.warn("连接断开 {}:{}", address, port);
        NameSrvClient.removeChannel(ctx.channel().id().asLongText());
        if (retryCount.get() < maxRetries) {
            scheduleReconnectWithBackoff(address, port, ctx.channel());
        } else {
            logger.error("达到最大重试次数，停止重连");
            ctx.close();
        }
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("发生异常断开连接: {}", cause.getMessage());
        ctx.close();
    }

    // 使用指数退避算法的重连方法
    private void scheduleReconnectWithBackoff(String address, int port, Channel channel) {
        final EventLoop loop = channel.eventLoop();

        // 计算延迟时间（指数退避）
        long delay = Math.min(initialDelay * (1L << retryCount.get()), maxDelay);

        logger.info("将在 {} 秒后尝试重新连接 {}:{} (第 {} 次重试)", delay, address, port, retryCount.incrementAndGet());

        reconnectFuture = loop.schedule(() -> {
            logger.info("正在尝试重新连接 {}:{}", address, port);
            try {
                ChannelFuture connectFuture = NameSrvClient.getChannel(address, port);
                connectFuture.addListener((ChannelFutureListener) future -> {
                    if (future.isSuccess()) {
                        Channel newChannel = future.channel();
                        NameSrvClient.addNameSrvChanel(newChannel);
                        logger.info("重连成功: {}:{}", address, port);
                        // 重连成功后重置计数器
                        retryCount.set(0);
                        cancelReconnect();
                    } else {
                        logger.warn("重连失败，准备进行下一次重连尝试");
                        // 如果重连失败，继续安排下一次重连
                        scheduleReconnectWithBackoff(address, port, channel);
                    }
                });
            } catch (Exception e) {
                logger.error("重连过程中发生异常: {}", e.getMessage());
                // 如果重连失败，继续安排下一次重连
                scheduleReconnectWithBackoff(address, port, channel);
            }
        }, delay, TimeUnit.SECONDS);
    }

    // 提供一个方法用于取消任务
    public void cancelReconnect() {
        if (reconnectFuture != null && !reconnectFuture.isCancelled()) {
            reconnectFuture.cancel(true);
            logger.info("已取消定时重连任务");
        }
    }
}
